home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 16
/
Aminet 16 (1996)(GTI - Schatztruhe)[!][Dec 1996].iso
/
Aminet
/
comm
/
term
/
term_source.lha
/
Extras
/
Source
/
term-source.lha
/
Serial.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-10-20
|
26KB
|
1,332 lines
/*
** Serial.c
**
** Serial driver support routines
**
** Copyright © 1990-1996 by Olaf `Olsen' Barthel
** All Rights Reserved
**
** :ts=4
*/
#ifndef _GLOBAL_H
#include "Global.h"
#endif
/* In case the DSR test is enabled */
STATIC BOOL UseRTS_CTS;
/* Serial write output routines */
STATIC SERWRITE SerWriteRoutine,SerWriteAndProcessRoutine;
STATIC VOID
WriteAndProcessUserMon(APTR Buffer,LONG Size)
{
Size = XProtocolUserMon(XprIO,Buffer,Size,Size);
if(Size > 0)
{
StartSerialWrite(Buffer,Size);
if(Marking)
WindowMarkerStop();
ConProcess(Buffer,Size);
WaitSerialWrite();
BytesOut += Size;
}
}
STATIC VOID
WriteUserMon(APTR Buffer,LONG Size)
{
Size = XProtocolUserMon(XprIO,Buffer,Size,Size);
if(Size > 0)
{
DoSerialWrite(Buffer,Size);
BytesOut += Size;
}
}
STATIC VOID
WriteAndProcessBypass(APTR Buffer,LONG Size)
{
if((*SerWriteBypass)(Buffer,Size))
{
StartSerialWrite(Buffer,Size);
ConProcess(Buffer,Size);
WaitSerialWrite();
BytesOut += Size;
}
}
STATIC VOID
WriteBypass(APTR Buffer,LONG Size)
{
if((*SerWriteBypass)(Buffer,Size))
{
DoSerialWrite(Buffer,Size);
BytesOut += Size;
}
}
STATIC VOID
WriteAndProcessBypassUserMon(APTR Buffer,LONG Size)
{
if((*SerWriteBypass)(Buffer,Size))
{
Size = XProtocolUserMon(XprIO,Buffer,Size,Size);
if(Size > 0)
{
StartSerialWrite(Buffer,Size);
ConProcess(Buffer,Size);
WaitSerialWrite();
BytesOut += Size;
}
}
}
STATIC VOID
WriteBypassUserMon(APTR Buffer,LONG Size)
{
if((*SerWriteBypass)(Buffer,Size))
{
Size = XProtocolUserMon(XprIO,Buffer,Size,Size);
if(Size > 0)
{
DoSerialWrite(Buffer,Size);
BytesOut += Size;
}
}
}
/* WriteAndProcess(APTR Buffer,LONG Size):
*
* At the same time write data to the serial port and
* process it on the screen.
*/
STATIC VOID
WriteAndProcess(APTR Buffer,LONG Size)
{
StartSerialWrite(Buffer,Size);
ConProcess(Buffer,Size);
WaitSerialWrite();
BytesOut += Size;
}
/* WriteDirect(APTR Buffer,LONG Size):
*
* Output the data and update the byte counter.
*/
STATIC VOID
WriteDirect(APTR Buffer,LONG Size)
{
DoSerialWrite(Buffer,Size);
BytesOut += Size;
}
/* SetFlags():
*
* Set the contents of a serial device request according
* to the current configuration settings.
*/
STATIC BYTE
SetFlags(VOID)
{
return(SetBothSerialAttributes(
SERA_Baud, Config->SerialConfig->BaudRate,
SERA_BreakTime, Config->SerialConfig->BreakLength,
SERA_BitsPerChar, Config->SerialConfig->BitsPerChar,
SERA_StopBits, Config->SerialConfig->StopBits,
SERA_BufferSize, Config->SerialConfig->SerialBufferSize,
SERA_Parity, Config->SerialConfig->Parity,
SERA_Handshaking, UseRTS_CTS ? Config->SerialConfig->HandshakingProtocol : HANDSHAKING_NONE,
SERA_HighSpeed, Config->SerialConfig->HighSpeed,
SERA_Shared, Config->SerialConfig->Shared,
TAG_DONE));
}
/* SendBreak():
*
* Transmit a break signal.
*/
VOID
SendBreak()
{
PushStatus(STATUS_BREAKING);
DoSerialCmd(SDCMD_BREAK);
PopStatus();
}
/* HangUp():
*
* Hang up the line.
*/
VOID
HangUp()
{
PushStatus(STATUS_HANGUP);
StopSerialWrite();
/* Are we to drop the DTR line
* before sending the hangup
* string?
*/
if(Config->ModemConfig->DropDTR)
{
if(!DropDTR(Config->SerialConfig->SerialDevice,Config->SerialConfig->UnitNumber))
{
DeleteSerial();
if(!ShowRequest(Window,LocaleString(MSG_TERMMAIN_FAILED_TO_REOPEN_UNIT_TXT),LocaleString(MSG_TERMMAIN_IGNORE_QUIT_TXT),Config->SerialConfig->SerialDevice,Config->SerialConfig->UnitNumber))
MainTerminated = TRUE;
}
}
/* Transmit the hangup command. */
if(Config->ModemConfig->ModemHangup[0] && !MainTerminated)
SerialCommand(Config->ModemConfig->ModemHangup);
/* Reset to old status. */
PopStatus();
}
/* CopyWriteFlags():
*
* Update configuration with serial settings.
*/
VOID
CopyWriteFlags()
{
ULONG Baud,
BreakTime,
BitsPerChar,
StopBits,
BufferSize,
Parity,
Handshaking,
HighSpeed,
Shared;
GetSerialWriteAttributes(
SERA_Baud, &Baud,
SERA_BreakTime, &BreakTime,
SERA_BitsPerChar, &BitsPerChar,
SERA_StopBits, &StopBits,
SERA_BufferSize, &BufferSize,
SERA_Parity, &Parity,
SERA_Handshaking, &Handshaking,
SERA_HighSpeed, &HighSpeed,
SERA_Shared, &Shared,
TAG_DONE);
Config->SerialConfig->BaudRate = Baud;
Config->SerialConfig->BreakLength = BreakTime;
Config->SerialConfig->BitsPerChar = BitsPerChar;
Config->SerialConfig->StopBits = StopBits;
Config->SerialConfig->SerialBufferSize = BufferSize;
Config->SerialConfig->Parity = Parity;
Config->SerialConfig->HandshakingProtocol = Handshaking;
Config->SerialConfig->HighSpeed = HighSpeed;
Config->SerialConfig->Shared = Shared;
}
/* SerWriteVerbatim(APTR Buffer,LONG Size,BOOL Echo):
*
* The `no fancy features' version of SerWrite().
*/
VOID
SerWriteVerbatim(APTR Buffer,LONG Size,BOOL Echo)
{
if(XProtocolBase && (TransferBits & XPRS_USERMON))
Size = XProtocolUserMon(XprIO,Buffer,Size,Size);
if(Size > 0)
{
if(Echo)
WriteAndProcess(Buffer,Size);
else
DoSerialWrite(Buffer,Size);
BytesOut += Size;
}
}
/* SerWriteUpdate():
*
* Choose the right data output routine for the job.
*/
VOID
SerWriteUpdate()
{
if(SerWriteBypass)
{
if(XProtocolBase && (TransferBits & XPRS_USERMON))
{
SerWriteRoutine = (SERWRITE)WriteBypassUserMon;
SerWriteAndProcessRoutine = (SERWRITE)WriteAndProcessBypassUserMon;
}
else
{
SerWriteRoutine = (SERWRITE)WriteBypass;
SerWriteAndProcessRoutine = (SERWRITE)WriteAndProcessBypass;
}
}
else
{
if(XProtocolBase && (TransferBits & XPRS_USERMON))
{
SerWriteRoutine = (SERWRITE)WriteUserMon;
SerWriteAndProcessRoutine = (SERWRITE)WriteAndProcessUserMon;
}
else
{
SerWriteRoutine = (SERWRITE)WriteDirect;
SerWriteAndProcessRoutine = (SERWRITE)WriteAndProcess;
}
}
}
/* SerWrite(APTR Buffer,LONG Size):
*
* Send a number of bytes across the serial line.
*/
VOID
SerWrite(APTR Buffer,LONG Size)
{
if(Size < 0)
Size = strlen(Buffer);
if(Size > 0)
{
if(RememberInput)
{
RememberInputText(Buffer,Size);
if(((UBYTE *)Buffer)[Size - 1] == '\r' && RecordingLine)
{
RememberSpill();
RecordingLine = FALSE;
RememberOutput = TRUE;
RememberInput = FALSE;
CheckItem(MEN_RECORD_LINE,FALSE);
}
}
else
{
if(RememberOutput)
{
RememberInputText(Buffer,Size);
RememberSpill();
}
}
if(WriteRequest)
{
if(SendTable)
{
struct TranslationHandle Handle;
UBYTE TranslateData[256];
/* Set up for buffer translation. */
TranslateSetup(&Handle,Buffer,Size,TranslateData,sizeof(TranslateData),SendTable);
/* Full or half duplex? */
if(Config->SerialConfig->Duplex == DUPLEX_FULL)
{
/* Process the data... */
while(Size = TranslateBuffer(&Handle))
(*SerWriteRoutine)(TranslateData,Size);
}
else
{
while(Size = TranslateBuffer(&Handle))
(*SerWriteAndProcessRoutine)(TranslateData,Size);
}
}
else
{
if(Config->SerialConfig->Duplex == DUPLEX_FULL)
(*SerWriteRoutine)(Buffer,Size);
else
(*SerWriteAndProcessRoutine)(Buffer,Size);
}
}
}
}
/* RestartSerial():
*
* Restart read/write activity on the serial line.
*/
VOID
RestartSerial()
{
/* Blow away the cache if there is anything left of it. */
if(DataHold)
{
DataHold = NULL;
UpdateSerialJob();
}
StartSerialRead(&ReadChar,1);
}
/* ClearSerial():
*
* Terminate all read/write activity on the serial line.
*/
VOID
ClearSerial()
{
/* Blow away the cache if there is anything left of it. */
if(DataHold)
{
DataHold = NULL;
UpdateSerialJob();
}
StopSerialRead();
FlushSerialRead();
}
/* DeleteSerial():
*
* Close the serial device and release all associated
* resources.
*/
VOID
DeleteSerial()
{
StopSerialRead();
StopSerialWrite();
if(ReadRequest)
{
if(ReadRequest->IOSer.io_Device)
{
UBYTE Name[MAX_FILENAME_LENGTH];
struct Device *Device;
/* Unless the device was opened in shared */
/* access mode we'll reset it here */
if(!Config->SerialConfig->Shared)
{
ReadRequest->IOSer.io_Command = CMD_RESET;
DoIO((struct IORequest *)ReadRequest);
}
/* Remember the device name, we'll need it after */
/* closing time */
LimitedStrcpy(sizeof(Name),Name,ReadRequest->IOSer.io_Device->dd_Library.lib_Node.ln_Name);
/* Close the device */
CloseDevice((struct IORequest *)ReadRequest);
/* And remove it from memory */
Forbid();
if(Device = (struct Device *)FindName(&SysBase->DeviceList,Name))
RemDevice(Device);
Permit();
}
DeleteIORequest(ReadRequest);
ReadRequest = NULL;
}
if(WriteRequest)
{
DeleteIORequest(WriteRequest);
WriteRequest = NULL;
}
if(WritePort)
{
DeleteMsgPort(WritePort);
WritePort = NULL;
}
if(ReadPort)
{
DeleteMsgPort(ReadPort);
ReadPort = NULL;
}
FreeVecPooled(ReadBuffer);
ReadBuffer = NULL;
FreeVecPooled(HostReadBuffer);
HostReadBuffer = NULL;
FreeVecPooled(StripBuffer);
StripBuffer = NULL;
UnlockDevice();
UpdateSerialJob();
}
/* GetSerialError(LONG Error,BOOL *Reset):
*
* Return an error message for each possible serial device error.
*/
STRPTR
GetSerialError(LONG Error,BOOL *ResetPtr)
{
BOOL Reset;
LONG ID;
Reset = FALSE;
ID = -1;
switch(Error)
{
case IOERR_BADLENGTH:
case IOERR_BADADDRESS:
case IOERR_SELFTEST:
case IOERR_OPENFAIL:
ID = MSG_SERIAL_OPENFAILURE_TXT;
break;
case SerErr_DevBusy:
ID = MSG_SERIAL_ERROR_DEVBUSY_TXT;
break;
case SerErr_BaudMismatch:
Reset = TRUE;
ID = MSG_SERIAL_ERROR_BAUDMISMATCH_TXT;
break;
case SerErr_BufErr:
Reset = TRUE;
ID = MSG_SERIAL_ERROR_BUFERR_TXT;
break;
case SerErr_InvParam:
Reset = TRUE;
ID = MSG_SERIAL_ERROR_INVPARAM_TXT;
break;
case SerErr_LineErr:
ID = MSG_SERIAL_ERROR_LINEERR_TXT;
break;
case SerErr_ParityErr:
Reset = TRUE;
ID = MSG_SERIAL_ERROR_PARITYERR_TXT;
break;
case SerErr_TimerErr:
ID = MSG_SERIAL_ERROR_TIMERERR_TXT;
break;
case SerErr_BufOverflow:
Reset = TRUE;
ID = MSG_SERIAL_ERROR_BUFOVERFLOW_TXT;
break;
case SerErr_NoDSR:
ID = MSG_SERIAL_ERROR_NODSR_TXT;
break;
/* case SerErr_UnitBusy: */
case IOERR_UNITBUSY:
case 16:
ID = MSG_SERIAL_ERROR_UNIT_BUSY_TXT;
break;
}
if(ID != -1)
{
if(ResetPtr)
*ResetPtr = Reset;
return(LocaleString(ID));
}
else
return(NULL);
}
/* CreateSerial():
*
* Create handles for the serial device and open it.
*/
BOOL
CreateSerial(STRPTR ErrorBuffer,LONG ErrorBufferSize)
{
BYTE Error = 0;
LONG ID = -1;
/* Try to lock the serial device driver if necessary */
if(Config->SerialConfig->UseOwnDevUnit && !(Config->SerialConfig->Shared && Config->SerialConfig->NoODUIfShared))
{
if(!LockDevice(Config->SerialConfig->SerialDevice,Config->SerialConfig->UnitNumber,ErrorBuffer,ErrorBufferSize))
return(FALSE);
}
/* Propagate the serial read buffer size to the translation routines */
Update_CR_LF_Translation();
/* Now allocate the required resources... */
if(ReadBuffer = AllocVecPooled(Config->SerialConfig->SerialBufferSize,MEMF_ANY))
{
if(StripBuffer = AllocVecPooled(Config->SerialConfig->SerialBufferSize,MEMF_ANY))
{
if(XProtocolBase && (TransferBits & XPRS_HOSTNOWAIT))
HostReadBuffer = AllocVecPooled(Config->SerialConfig->SerialBufferSize,MEMF_ANY);
if(ReadPort = (struct MsgPort *)CreateMsgPort())
{
if(ReadRequest = (struct IOExtSer *)CreateIORequest(ReadPort,sizeof(struct IOExtSer)))
{
if(WritePort = (struct MsgPort *)CreateMsgPort())
{
if(WriteRequest = (struct IOExtSer *)CreateIORequest(WritePort,sizeof(struct IOExtSer)))
{
/* Unless the user doesn't want RTS/CTS handshaking */
/* we'll assume it should be enabled. This also concerns */
/* the RTS/CTS+DSR test mode which will also start */
/* with having RTS/CTS handshaking enabled. */
UseRTS_CTS = (BOOL)(Config->SerialConfig->HandshakingProtocol != HANDSHAKING_NONE);
/* Set the default opening parameters */
SetSerialReadAttributes(
SERA_Baud, Config->SerialConfig->BaudRate,
SERA_BreakTime, Config->SerialConfig->BreakLength,
SERA_BitsPerChar, Config->SerialConfig->BitsPerChar,
SERA_StopBits, Config->SerialConfig->StopBits,
SERA_BufferSize, Config->SerialConfig->SerialBufferSize,
SERA_Parity, Config->SerialConfig->Parity,
SERA_Handshaking, Config->SerialConfig->HandshakingProtocol,
SERA_HighSpeed, Config->SerialConfig->HighSpeed,
SERA_Shared, Config->SerialConfig->Shared,
TAG_DONE);
/* Open the device driver */
if(!(Error = OpenSerialDevice(Config->SerialConfig->SerialDevice,Config->SerialConfig->UnitNumber)))
{
/* Should we perform a DSR signal test before */
/* proceeding? */
if(Config->SerialConfig->HandshakingProtocol == HANDSHAKING_RTSCTS_DSR)
{
/* Now check if the DSR signal is enabled. */
if(GetSerialStatus() & CIAF_COMDSR)
{
/* If this is the first time the driver gets initialized, */
/* skip the notification message and just drop the RTS/CTS */
/* handshaking bit. */
if(FirstInvocation)
UseRTS_CTS = FALSE;
else
{
do
{
if(!ShowRequest(Window,LocaleString(MSG_SERIAL_NO_DSR_SIGNAL_TXT),LocaleString(MSG_SERIAL_RETRY_CANCEL_TXT)))
UseRTS_CTS = FALSE;
}
while(UseRTS_CTS && (GetSerialStatus() & CIAF_COMDSR));
}
}
}
/* Update the driver data */
ResetSerialRead();
ResetSerialWrite();
/* Set the parameters */
SetFlags();
/* And ask for a byte */
RestartSerial();
UpdateSerialJob();
return(TRUE);
}
}
}
else
ID = MSG_SERIAL_FAILED_TO_CREATE_WRITE_PORT_TXT;
}
}
else
ID = MSG_SERIAL_FAILED_TO_CREATE_READ_PORT_TXT;
}
}
/* If we get here something must be wrong. */
DeleteSerial();
/* If we got an open error, we'll try to make it into */
/* a readable description */
if(Error != 0)
{
STRPTR String;
if(!(String = GetSerialError(Error,NULL)))
String = LocaleString(MSG_SERIAL_ERROR_DEVBUSY_TXT);
LimitedSPrintf(ErrorBufferSize,ErrorBuffer,String,Config->SerialConfig->SerialDevice,Config->SerialConfig->UnitNumber);
}
else
{
/* If no open error has occured a problem must have */
/* hit us before the device was ready to open. */
/* If the error message ID is negative we'll use the */
/* default message which indicates memory allocation */
/* problems. */
if(ID == -1)
ID = MSG_SERIAL_NOT_ENOUGH_MEMORY_TXT;
strcpy(ErrorBuffer,LocaleString(ID));
}
return(FALSE);
}
/* ReconfigureSerial(struct Window *Window,struct SerialSettings *SerialConfig):
*
* Reconfigure the serial driver according to the new
* serial settings.
*/
LONG
ReconfigureSerial(struct Window *Window,struct SerialSettings *SerialConfig)
{
LONG Success = RECONFIGURE_NOCHANGE;
/* Are new settings to be installed or have they already */
/* been copied to the correct locations? */
if(CompareConfigEntries(Config->SerialConfig,SerialConfig ? SerialConfig : PrivateConfig->SerialConfig,PREF_SERIAL))
{
BOOL SameDevice = TRUE;
/* Any new data to swap in? */
if(SerialConfig)
{
/* Store the previous settings. */
SaveConfig(Config,PrivateConfig);
/* Install the new settings */
PutConfigEntry(Config,SerialConfig,PREF_SERIAL);
}
/* Any device name or unit number change? */
if(strcmp(PrivateConfig->SerialConfig->SerialDevice,Config->SerialConfig->SerialDevice) || PrivateConfig->SerialConfig->UnitNumber != Config->SerialConfig->UnitNumber || PrivateConfig->SerialConfig->UseOwnDevUnit != Config->SerialConfig->UseOwnDevUnit)
SameDevice = FALSE;
/* Handshaking mode changed? */
if((PrivateConfig->SerialConfig->HandshakingProtocol == HANDSHAKING_NONE && Config->SerialConfig->HandshakingProtocol != HANDSHAKING_NONE) || (PrivateConfig->SerialConfig->HandshakingProtocol != HANDSHAKING_NONE && Config->SerialConfig->HandshakingProtocol == HANDSHAKING_NONE))
SameDevice = FALSE;
/* Did the ODU options change? */
if(PrivateConfig->SerialConfig->NoODUIfShared != Config->SerialConfig->NoODUIfShared && Config->SerialConfig->Shared)
SameDevice = FALSE;
/* Is the device currently closed, i.e. should we open it? */
if(!ReadRequest)
SameDevice = FALSE;
/* Stop any IO activity. */
ClearSerial();
/* No dramatic changes? Simply change the parameters. */
if(SameDevice)
{
LONG Error;
/* Did the buffer size change? */
if(PrivateConfig->SerialConfig->SerialBufferSize != Config->SerialConfig->SerialBufferSize)
{
STRPTR NewReadBuffer;
STRPTR NewStripBuffer;
/* Allocate two new buffers */
NewReadBuffer = AllocVecPooled(Config->SerialConfig->SerialBufferSize,MEMF_ANY);
NewStripBuffer = AllocVecPooled(Config->SerialConfig->SerialBufferSize,MEMF_ANY);
/* Did we get both? */
if(NewReadBuffer && NewStripBuffer)
{
/* Release the old buffers */
FreeVecPooled(ReadBuffer);
FreeVecPooled(StripBuffer);
/* And put the new ones in */
ReadBuffer = NewReadBuffer;
StripBuffer = NewStripBuffer;
}
else
{
/* Release whatever we had allocated */
FreeVecPooled(NewReadBuffer);
FreeVecPooled(NewStripBuffer);
/* And change back to the old buffer size */
Config->SerialConfig->SerialBufferSize = PrivateConfig->SerialConfig->SerialBufferSize;
}
}
/* Propagate the buffer size to the translation routines */
Update_CR_LF_Translation();
/* Use new parameters */
if(Error = SetFlags())
{
UBYTE LocalBuffer[256];
STRPTR String;
BOOL Reset;
/* Get the error message. */
if(!(String = GetSerialError(Error,&Reset)))
String = LocaleString(MSG_SERIAL_ERROR_DEVBUSY_TXT);
/* Build the device name/unit number string. */
LimitedSPrintf(sizeof(LocalBuffer),LocalBuffer,String,Config->SerialConfig->SerialDevice,Config->SerialConfig->UnitNumber);
/* Display the error requester. */
ShowRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),LocalBuffer);
/* Is a serial driver reset required? */
if(Reset)
{
/* Execute the reset command. */
DoSerialCmd(CMD_RESET);
/* Copy the serial driver settings */
/* to the global configuration. */
CopyWriteFlags();
/* Also set the read request driver flags */
SetFlags();
}
}
/* Restart read request */
RestartSerial();
}
else
{
UBYTE LocalBuffer[256];
/* Shut down the serial device driver */
DeleteSerial();
/* Reinitialize the serial device driver */
if(!CreateSerial(LocalBuffer,sizeof(LocalBuffer)))
{
/* Display the error requester */
ShowRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_GLOBAL_CONTINUE_TXT),LocalBuffer);
/* That didn't work */
Success = RECONFIGURE_FAILURE;
}
}
}
return(Success);
}
/* ReopenSerial():
*
* Reopen the serial driver.
*/
VOID
ReopenSerial()
{
BOOL SerialClosed = TRUE;
UBYTE LocalBuffer[256];
do
{
if(CreateSerial(LocalBuffer,sizeof(LocalBuffer)))
SerialClosed = FALSE;
else
{
switch(ShowRequest(Window,LocaleString(MSG_GLOBAL_TERM_HAS_A_PROBLEM_TXT),LocaleString(MSG_TERMMAIN_RETRY_IGNORE_QUIT_TXT),LocalBuffer))
{
case 0:
MainTerminated = TRUE;
break;
case 2:
SerialClosed = FALSE;
break;
}
}
}
while(SerialClosed && !MainTerminated);
}
/* HandleSerialJob():
*
* Handle the data coming in from the serial line.
*/
BOOL
HandleSerialJob(JobNode *UnusedJob)
{
BOOL MoreData;
if(HostReadBuffer)
{
LONG Length = XProtocolHostMon(XprIO,HostReadBuffer,0,SerialBufferSize);
if(Translate_CR_LF && Length > 0)
Length = (*Translate_CR_LF)(HostReadBuffer,Length);
if(Length > 0)
{
ConProcess(HostReadBuffer,Length);
if(Get_xOFF())
return(FALSE);
}
MoreData = TRUE;
}
else
MoreData = FALSE;
/* Any news? */
if(CheckSerialRead())
{
/* Terminate the read request properly. */
if(!WaitSerialRead())
{
ULONG Length;
/* We got another byte. */
ReadBuffer[0] = ReadChar;
/* Check if there is anything waiting to be read. */
if(Length = GetSerialWaiting())
{
ULONG MaxSize;
/* This is how many characters fill still fit into
* the read buffer.
*/
MaxSize = SerialBufferSize - 1;
/* Check if there is more data waiting
* than will fit into the buffer.
*/
if(Length > MaxSize)
Length = MaxSize;
/* Check if there is more data waiting than
* the serial quantum allows.
*/
if(Length > Config->SerialConfig->Quantum)
Length = Config->SerialConfig->Quantum;
/* Read the data still waiting. */
if(DoSerialRead(&ReadBuffer[1],Length))
Length = 0;
}
/* One byte was added earlier. */
Length++;
/* Process the data. */
BytesIn += Length;
(*ConTransfer)(ReadBuffer,Length);
}
/* If something is in the cache, don't overwrite
* it by requesting another byte. Serial I/O
* processing will be restarted when the cache
* gets drained.
*/
if(!DataHold && ProcessIO)
{
/* Yes, there is more to come. */
MoreData = TRUE;
StartSerialRead(&ReadChar,1);
}
}
return(MoreData);
}
/* UpdateSerialJob():
*
* Either activate or suspend the serial I/O job.
*/
VOID
UpdateSerialJob()
{
ULONG Mask;
if(!Get_xOFF() && ReadPort && ProcessIO)
Mask = SIG_SERIAL;
else
Mask = NULL;
if(Mask)
{
if(DataHold)
{
Mask = NULL;
ActivateJob(MainJobQueue,SerialCacheJob);
}
else
SuspendJob(MainJobQueue,SerialCacheJob);
}
UpdateJob(MainJobQueue,SerialJob,Mask);
/* Now pick the right simplified access routines
* for the job.
*/
if(DataHold)
{
SerialWaitForData = SerialCacheWaitForData;
SerialGetWaiting = SerialCacheGetWaiting;
SerialRead = SerialCacheRead;
}
else
{
SerialWaitForData = SerialStdWaitForData;
SerialGetWaiting = SerialStdGetWaiting;
SerialRead = SerialStdRead;
}
}
/* HandleSerialCacheJob(JobNode *UnusedJob):
*
* Does what HandleSerialJob() does, but picks the
* data from the cache.
*/
BOOL
HandleSerialCacheJob(JobNode *UnusedJob)
{
STRPTR Data = DataHold;
LONG Size = DataSize;
/* These two are no longer valid. */
DataHold = NULL;
DataSize = 0;
/* If there was anything in the buffer,
* process it.
*/
if(Size > 0)
(*ConTransfer)(Data,Size);
RestartSerial();
UpdateSerialJob();
return(TRUE);
}
/**********************************************************************/
/* SerialStdWaitForData(ULONG OtherBits):
*
* Wait for new data to arrive or other events to
* take place.
*/
ULONG
SerialStdWaitForData(ULONG OtherBits)
{
return(Wait(SIG_SERIAL | OtherBits));
}
/* SerialCacheWaitForData(ULONG OtherBits):
*
* Checks if other events took place and always flag
* new serial data to be available.
*/
ULONG
SerialCacheWaitForData(ULONG OtherBits)
{
return((SetSignal(0,OtherBits) & OtherBits) | SIG_SERIAL);
}
/* SerialStdGetWaiting():
*
* Get the number of bytes still waiting to be read.
*/
ULONG
SerialStdGetWaiting()
{
return(GetSerialWaiting());
}
/* SerialCacheGetWaiting():
*
* Return the number of bytes still in the cache and
* the number of bytes waiting in the serial read
* buffer.
*/
ULONG
SerialCacheGetWaiting()
{
return(DataSize + SerialStdGetWaiting());
}
/* SerialStdRead(UBYTE *Buffer,LONG Len):
*
* Reads a number of bytes from the serial line and
* puts them into the buffer. This routine assumes a
* read request had been queued earlier. It waits
* for the queued request to terminate, grabs the
* character that was read and fills the remaining
* buffer with the data to follow. Eventually, the
* read request gets queued again.
*/
LONG
SerialStdRead(UBYTE *Buffer,LONG Len)
{
LONG Total;
/* Wait for the read request to terminate. */
WaitSerialRead();
/* Put the byte into the buffer. */
*Buffer++ = ReadChar;
Len--;
/* So far, one byte was read. */
Total = 1;
/* Any more data requested? */
if(Len > 0)
{
/* Read the rest. */
if(!DoSerialRead(Buffer,Len))
Total += Len;
}
/* Restart the read request. */
StartSerialRead(&ReadChar,1);
/* Return the number of bytes read so far. */
return(Total);
}
/* SerialCacheRead(UBYTE *Buffer,LONG Size):
*
* Read a number of bytes from the cache and the
* serial buffer. Switch back to normal operation
* if the cache is exhausted.
*/
LONG
SerialCacheRead(UBYTE *Buffer,LONG Size)
{
LONG Total;
/* Nothing has been read yet. */
Total = 0;
/* Check if there is anything left in the cache. */
if(DataSize > 0)
{
LONG Count;
/* If there is more data in the cache than
* requested, just read the requested number
* of bytes from it.
*/
if(DataSize > Size)
Count = Size;
else
Count = DataSize;
/* Copy the data from the cache into the buffer. */
CopyMem(DataHold,Buffer,Count);
/* This is how many bytes went into the buffer so far. */
Total += Count;
/* Update the buffer data. */
Buffer += Count;
Size -= Count;
/* Update the cache data. */
DataHold += Count;
DataSize -= Count;
}
/* If no data is left in the cache, switch the read routines
* back to the standard versions. This is done inside
* RestartSerial().
*/
if(DataSize == 0)
RestartSerial();
/* If there is still data to be read, read it from the standard
* channel, otherwise return the number of bytes already read.
*/
if(Size > 0)
return(Total + SerialStdRead(Buffer,Size));
else
return(Total);
}